<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>闭包</title>
</head>

<body>
	<script>
		// 闭包的定义：闭包是指一个函数可以访问其外部作用域的变量，即使外部函数已经返回。
		// 这通常是通过在函数内部定义另一个函数来实现的。

		// 示例：
		// 1. 基本的闭包示例
		function outerFunction() {
			let outerVariable = 'I am from outer function!'; // 外部变量

			// 定义一个内部函数
			function innerFunction() {
				console.log(outerVariable); // 访问外部变量
			}

			return innerFunction; // 返回内部函数
		}

		const closureFunction = outerFunction(); // 调用外部函数，返回内部函数
		closureFunction(); // 调用内部函数，输出：I am from outer function!


		// 2. 闭包的应用：数据私有化
		function createCounter() {
			let count = 0; // 私有变量

			return {
				increment: function () {
					count++; // 修改私有变量
					console.log(count);
				},
				decrement: function () {
					count--; // 修改私有变量
					console.log(count);
				},
				getCount: function () {
					return count; // 访问私有变量
				}
			};
		}

		const counter = createCounter(); // 创建计数器对象
		counter.increment(); // 输出：1
		counter.increment(); // 输出：2
		counter.decrement(); // 输出：1
		console.log(counter.getCount()); // 输出：1


		// 3. 闭包的应用：函数工厂
		function makeMultiplier(factor) {
			return function (x) {
				return x * factor; // 使用外部变量
			};
		}
		const double = makeMultiplier(2); // 创建一个乘以2的函数
		const triple = makeMultiplier(3); // 创建一个乘以3的函数
		console.log(double(5)); // 输出：10
		console.log(triple(5)); // 输出：15

		// 4. 闭包的应用：延迟执行
		function delayedGreeting(name) {
			return function () {
				console.log(`Hello, ${name}!`); // 使用外部变量
			};
		}
		const greetJohn = delayedGreeting('John'); // 创建一个延迟问候函数
		setTimeout(greetJohn, 1000); // 1秒后输出：Hello, John!

		// 5. 闭包的应用：事件处理器
		function createButtonHandler(buttonId) {
			return function () {
				console.log(`Button ${buttonId} clicked!`); // 使用外部变量
			};
		}
		const button1Handler = createButtonHandler(1); // 创建按钮1的事件处理器
		const button2Handler = createButtonHandler(2); // 创建按钮2的事件处理器

		button1Handler(); // 输出：Button 1 clicked!
		button2Handler(); // 输出：Button 2 clicked!


	</script>
</body>

</html>